package com.rf.richfitwheel.admin.sys.controller;

import com.rf.richfitwheel.admin.contants.UrlConstant;
import com.rf.richfitwheel.admin.sys.model.CodeUseInfo;
import com.rf.richfitwheel.admin.sys.service.CodeDefService;
import com.rf.richfitwheel.admin.sys.service.CodeUseInfoService;
import com.rf.richfitwheel.admin.sys.service.GenerateIDUtil;
import com.rf.richfitwheel.admin.sys.service.impl.CodeUseInfoServiceImpl;
import com.rf.richfitwheel.common.utils.PageUtils;
import com.rf.richfitwheel.common.utils.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * Author bw
 * Date  2019-05-05
 */
@RestController
@RequestMapping(value = UrlConstant.WEB_ADMIN_URL+"/codeUseInfo")
public class CodeUseInfoController {
	private static Logger log = LoggerFactory.getLogger(CodeUseInfoServiceImpl.class);
    @Autowired
    private CodeUseInfoService codeUseInfoService;
    @Autowired
    private CodeDefService codeDefService;
	
	@Resource
	private GenerateIDUtil redisGenerateIDUtil;
	
//	private Lock lock = new ReentrantLock();

    /**
     * 根据编码编号获取使用列表
     * @param params
     * @return
     */
    @GetMapping("/list")
    public R list(@RequestParam Map<String, Object> params) {
    	PageUtils page = codeUseInfoService.queryPage(params);
		return R.ok().put("page", page);
    }
    
    @PostMapping("/update")
    public R update(@RequestParam Map<String, Object> params) {
    	try {
    		String id = (String) params.get("codeId");
    		CodeUseInfo cui = new CodeUseInfo();
    		cui.setId(id);
    		cui.setUseflag("1");
			codeUseInfoService.update(cui);
			return R.ok();
		} catch (Exception e) {
			e.printStackTrace();
			return R.error();
		}
    }
    
    /**
     * 获得编码和回收编码
     * @param params {code:编码编号，param:参数，逗号分隔,codes:编码串，回收时要用，逗号分隔，num: 数量，批量获取编号用,op: 操作类型}
     * @return
     */
    @PostMapping("/codeTest")
    public R codeTest(@RequestParam Map<String, Object> params) {
//    	lock.lock();
//		单机锁并不能解决多节点部署的问题，已在service层程序中增加分布式锁的实现
		try{
			String op = (String) params.get("op");
			String code = (String) params.get("code");
			String codes = (String) params.get("codes");
			String param = (String) params.get("param");
			String num = (String) params.get("num");
			String str="";
			//生成单个编号
			if("getOne".equals(op)) {
				param = param.trim();
				param = param.replace("，", ",");
				str =  codeUseInfoService.getOne(code,param);
//				System.out.println(str);
			}
			 //生成单个编号
			if("getOneButNotAdd".equals(op)) {
				param = param.trim();
				param = param.replace("，", ",");
				Map<String, Object> map = codeUseInfoService.getOneButNotAdd(codes, param);
//				System.out.println(str);
				return R.ok().put("map", map);
			}

			//批量生成编号
			if("getBatch".equals(op)) {
				if(num == null || "".equals(num)){
					num = "1";
				}
				List<String> listR = codeUseInfoService.getBacth(code,param,Integer.parseInt(num));
				if(listR != null && !listR.isEmpty()) {
					for(String s : listR){
						str += (s + ",");
					}
				}
			}

			//回收单个编号
			if(op.equals("setOne")){
				codes = codes.trim();
				str = codeUseInfoService.setOne(code,codes);
			}

			//批量回收编号
			if(op.equals("setBatch")){
				codes = codes.trim();
				codes = codes.replace("，", ",");
				str = codeUseInfoService.setBatch(code,codes);
			}

			if(str!=null&&!"".equals(str)) {
				return R.ok().put("str", str);
			}else {
				return R.error().put("msg", "操作失败，请检查输入是否有误！");
			}
		}catch(Exception e) {
			return R.error().put("msg", "操作失败，请检查输入是否有误！");
		}
    }
	
	/**
	 * 测试用的获取编码方法，业务切勿使用
	 * @return
	 */
	@PostMapping("/codeTestMe")
	public R codeTestMe() {
		String op = "getOne";
		String code = "SETT-FKSQ";
		String param = "";
		String str1="";
		String str2="";
		String str3="";
		//连续取20次做实验
		for(int i = 0; i < 20; i++){
			//生成单个编号
			TestThread th = new TestThread(codeUseInfoService, code, param, i+1);
			new Thread(th).start();
			TestThread th1 = new TestThread(codeUseInfoService, code, param, i+1);
			new Thread(th1).start();
		}
		return R.ok("调用方法成功");
	}
	
	public class TestThread implements Runnable{
		private CodeUseInfoService codeUseInfoService;
		private String code;
		private String paramMe;
		private int count;
		public TestThread(CodeUseInfoService codeUseInfoService, String code, String paramMe, int count){
			this.codeUseInfoService = codeUseInfoService;
			this.code = code;
			this.paramMe = paramMe;
			this.count = count;
		}
		
		@Override
		public void run(){
			this.paramMe = this.paramMe.trim();
			this.paramMe = this.paramMe.replace("，", ",");
			String sss = this.codeUseInfoService.getOne(this.code, this.paramMe);
			System.out.println(sss);
			/*long start1 = System.currentTimeMillis();
			List<String> list = this.codeUseInfoService.getBacth(this.code, this.paramMe, 100);
			long end1 = System.currentTimeMillis();
			log.info("第一种方式，共用时{}秒{}毫秒................", (end1-start1)/1000, (end1-start1));
			log.info("第{}次第一种方式str:{}:{}", count, DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN), list);
			long start2 = System.currentTimeMillis();
			List<String> list2 = this.codeUseInfoService.getBacthFromOne(this.code, this.paramMe, 100);
			long end2 = System.currentTimeMillis();
			log.info("第二种方式，共用时{}秒{}毫秒................", (end2-start2)/1000, (end2-start2));
			log.info("第{}次第一种方式str:{}:{}", count, DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN), list2);*/
		}
	}
	
	/**
	 * 测试分布式全局id获取，单个
	 * @return 结果
	 */
	@GetMapping("/testRedisGenerateIDUtilSingle")
	public R testRedisGenerateIDUtilSingle() {
		try{
			// 定义一个线程池 设置核心线程数和最大线程数都为100，队列根据需要设置
			ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 100, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(5000));
			CountDownLatch countDownLatch = new CountDownLatch(5000);
			
			long beginTime = System.currentTimeMillis();
			// 获取10000个全局唯一ID 看看是否有重复
			CopyOnWriteArraySet<String> ids = new CopyOnWriteArraySet<>();
			for (int i = 0; i < 5000; i++) {
				executor.execute(() -> {
					// 获取全局唯一ID
					long beginTime02 = System.currentTimeMillis();
					String orderNo = redisGenerateIDUtil.generateId("FKSQ", "4", 4);
					System.out.println("获取单个ID耗时 time=" + (System.currentTimeMillis() - beginTime02));
					if (ids.contains(orderNo)) {
						System.out.println("重复ID=" + orderNo);
					} else {
						ids.add(orderNo);
					}
					countDownLatch.countDown();
				});
			}
			countDownLatch.await();
			// 打印获取到的全局唯一ID集合数量
			System.out.println("获取到全局唯一ID count=" + ids.size());
			System.out.println("耗时毫秒 time=" + (System.currentTimeMillis() - beginTime));
			System.out.println(ids);
			return R.ok();
		}catch(Exception e){
			log.error(e.getMessage(), e);
			return R.ok();
		}
	}
	
	/**
	 * 返回一个业务编号
	 * @param code 前缀
	 * @param type 1-code+length位数字，2-code+YYYY+length位数字，3-code+YYYYMM+length位数字，
	 *      *               4-code+YYYYMMDD+length位数字
	 * @param length 数字长度
	 * @return 业务编号
	 */
	@GetMapping("/getBusGenerateCodeOne/{code}/{type}/{length}")
	public String getBusGenerateCode(@PathVariable("code") String code, @PathVariable("type") String type, @PathVariable("length") int length){
		return redisGenerateIDUtil.generateId(code, type, length);
	}
	
	/**
	 * 返回一个业务编号
	 * @param code 前缀
	 * @param type 1-code+length位数字，2-code+YYYY+length位数字，3-code+YYYYMM+length位数字，
	 *      *               4-code+YYYYMMDD+length位数字
	 * @param length 数字长度
	 * @param count 数量
	 * @return 业务编号
	 */
	@GetMapping("/getBusGenerateCodeBatch/{code}/{type}/{length}/{count}")
	public List<String> getBusGenerateCode(@PathVariable("code") String code, @PathVariable("type") String type, @PathVariable("length") int length, @PathVariable("count") int count){
		return redisGenerateIDUtil.generateIdBatch(code,type,count, length);
	}
}
